﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using UnityEngine.Video;
using System.IO;
using System;
using UnityEngine.SceneManagement;
using System.Diagnostics;
using Debug = UnityEngine.Debug;

public enum Language
{
    CN,
    EN,
}

public class LunBoTu2 : MonoBehaviour
{
    public Transform cameraTran;            // 相机transform
    public GameObject centerObj;            // 中心物体，地球
    public Transform uiParent;              // UI父级，与中心物体在一个位置
    public GameObject objectToInstantiate;  // 要实例化的物体预制件
    public int numberOfObjects = 10;        // 物体数量
    public float radius = 5f;               // 圆的半径

    public Button startBtn;
    public Button endBtn;
    public Button cnBtn;
    public Button enBtn;
    public Button btn_ToLauncher;
    public Image animImg;

    private const int min = 0;
    private const int max = 146;

    private int current;
    private string effect;

    private bool isInited = false;
    private bool isStarting;
    private bool isEnding;
    private float endInitRot = 0;

    private List<GameObject> uiObjs;        // 加载出来的UI列表
    private Vector3 lastMousePos;           // 上次鼠标位置
    private float rotSpeed;                 // 旋转速度

    private bool systemCtrl;                // 系统控制中（开始和结束动画）
    private int choosedIndex;               // 选中的索引

    private Tween uiParentTween;

    private Language language = Language.EN;

    // 未选中时的最小速度
    private static float MIN_SPEED = 1f;
    // 未选中时的最大速度
    private static float MAX_SPEED = 2f;
    // 鼠标默认位置
    private static Vector3 INIT_POS_VALUE = Vector3.one * int.MinValue;
    // 速度系数
    private static float SPEED_COE = -0.002f;

    private static float Normal_Scale = 0.0015f;
    private static float Big_Scale = 0.003f;

    private static List<float> SPEED_ATTENUATION_LEVEL = new List<float>() { 2, 6, 15, 30, 50 };    // 速度衰减档位
    private static List<float> SPEED_ATTENUATION_COE = new List<float>() { 1f, 4, 10, 18, 30 };     // 速度衰减系数

    private static List<string> Videos = new List<string>
    {
        "china",
        "england",
        "france",
        "germany",
        "israel",
        "japan",
        "usa"
    };

    private void Awake()
    {
        QualitySettings.vSyncCount = 2;

        Screen.sleepTimeout = SleepTimeout.NeverSleep;
        Application.runInBackground = true;
        //设置日志
        Debug.unityLogger.logEnabled = true;
        Application.targetFrameRate = 45;


        choosedIndex = -1;
        isStarting = false;
        isEnding = false;
        uiObjs = new List<GameObject>();
        lastMousePos = INIT_POS_VALUE;
        rotSpeed = 0;
        systemCtrl = false;
    }

    private async void Start()
    {
        await ConfigHelper.LoadConfigAsync();
        language = AppConst.language;
        MAX_SPEED = AppConst.MAX_SPEED;
        MIN_SPEED = AppConst.MIN_SPEED;
        SPEED_COE = AppConst.SPEED_COE;
        cnBtn.gameObject.SetActive(language == Language.EN);
        enBtn.gameObject.SetActive(language == Language.CN);
        CreateUI();
        PlayAnim();
        OnStartClick();

        cnBtn.onClick.AddListener(OnCNClick);
        enBtn.onClick.AddListener(OnENClick);

        btn_ToLauncher.onClick.AddListener(OnToLauncherClicked);
    }

    #region 跳转到启动器
    private void OnToLauncherClicked()
    {
        //panelMgr.CloseAllPanel();
        //panelMgr.OpenPanel<UILanguageCtrl>();

        var file = $"{GetRootDirectory()}/{AppConst.launcher}";
        LaunchExternalExe(file);
        Application.Quit();
    }

    private string GetRootDirectory()
    {
        string parentDirectory;

        // 判断是否是编辑器环境
        if (Application.isEditor)
        {
            // 编辑器模式下，获取项目根目录的上级目录（示例）
            string projectPath = Directory.GetParent(Application.dataPath).FullName;
            parentDirectory = Directory.GetParent(projectPath).FullName;
            Debug.Log("编辑器模式，项目根目录的上级目录: " + parentDirectory);
        }
        else
        {
            // 打包后，通过EXE路径获取
            string exePath = Process.GetCurrentProcess().MainModule.FileName;
            string exeDirectory = Path.GetDirectoryName(exePath);
            parentDirectory = Directory.GetParent(exeDirectory).FullName;
            Debug.Log("EXE上级目录: " + parentDirectory);
        }
        return parentDirectory;
    }

    private void LaunchExternalExe(string exePath)
    {
        // 檢查文件是否存在
        if (!File.Exists(exePath))
        {
            Debug.LogError($"EXE文件不存在於路徑: {exePath}");
            return;
        }

        // 配置進程啟動參數
        var startInfo = new ProcessStartInfo
        {
            FileName = exePath,
            WorkingDirectory = Path.GetDirectoryName(exePath), // 設置工作目錄
            Arguments = "arg1 arg2", // 可選參數
            UseShellExecute = true // 允許使用系統外殼執行
        };

        try
        {
            // 啟動進程
            using Process process = Process.Start(startInfo);
            Debug.Log("EXE啟動成功！");
        }
        catch (System.Exception e)
        {
            Debug.LogError($"啟動EXE失敗: {e.Message}");
        }
    }
    #endregion

    private void PlayAnim()
    {
        if (language == Language.CN)
        {
            effect = "Sprites/Chinese/中文_";
        }
        else
        {
            effect = "Sprites/English/英文_";
        }
        current = min;
        InitEffects();
    }

    private void SetEffects()
    {
        if (isInited)
        {
            return;
        }
        current++;
        if (current > max)
        {
            isInited = true;
            //// 帧动画结束
            //OnStartClick();
            //startBtn.onClick.AddListener(OnStartClick);
            endBtn.onClick.AddListener(OnEndClick);

            //cnBtn.onClick.AddListener(OnCNClick);
            //enBtn.onClick.AddListener(OnENClick);
            return;
        }
        InitEffects();
    }

    private void InitEffects()
    {
        var file = $"{effect}{current:d5}";
        animImg.sprite = Resources.Load<Sprite>(file);
    }

    private void CreateUI()
    {
        for (int i = 0; i < numberOfObjects; i++)
        {
            float angle = 360f / numberOfObjects * i * Mathf.Deg2Rad;                                   // 计算每个物体的角度
            Vector3 position = new Vector3(-Mathf.Sin(angle) * radius, 0, -Mathf.Cos(angle) * radius);    // 计算每个物体的位置
            GameObject newUIObj = Instantiate(objectToInstantiate, centerObj.transform.position + position, Quaternion.identity);
            newUIObj.name = i.ToString();
            newUIObj.SetActive(false);
            newUIObj.transform.parent = uiParent;
            newUIObj.transform.LookAt(cameraTran.position);
            //newUIObj.transform.Find("Canvas/Image").GetComponent<Image>().color = new Color(1 - (i / (float)numberOfObjects), 0, 0, 1 - (i / (float)numberOfObjects));
            newUIObj.transform.Find("Canvas/Image").GetComponent<Button>().onClick.AddListener(delegate { OnItemClick(newUIObj); });
            newUIObj.transform.Find("Canvas/Image/Text").GetComponent<Text>().text = i.ToString();
            RenderTexture renderTexture = new RenderTexture(1920, 1080, 0);
            newUIObj.transform.Find("Canvas/Image/ImageMask/RawImage").GetComponent<RawImage>().texture = renderTexture;
            VideoPlayer videoPlayer = newUIObj.transform.Find("Canvas/Image/VideoPlayer").GetComponent<VideoPlayer>();
            videoPlayer.targetTexture = renderTexture;
            videoPlayer.source = VideoSource.Url;
            if (Videos.Count > i)
            {
                videoPlayer.loopPointReached += VideoEnd;
                string spritePath = "Sprites/" + Videos[i];
                var image = newUIObj.transform.Find("Canvas/Image/Image").GetComponent<Image>();
                image.sprite = Resources.Load<Sprite>(spritePath);
                image.gameObject.SetActive(true);
                string nameSpritePath = "Sprites/ContrName/" + (language == Language.CN ? "cn_" : "en_") + Videos[i];
                var nameImage = newUIObj.transform.Find("Canvas/Image/NameImage").GetComponent<Image>();
                nameImage.sprite = Resources.Load<Sprite>(nameSpritePath);
                nameImage.SetNativeSize();
                string path = Path.Combine(Application.streamingAssetsPath, "Videos/" + Videos[i] + ".mp4");
                videoPlayer.url = path;
            }
            uiObjs.Add(newUIObj);
        }
    }

    private void OnItemClick(GameObject obj)
    {
        if (uiParentTween != null)
        {
            uiParentTween.Kill();
            uiParentTween = null;
            systemCtrl = false;
        }

        int index = int.Parse(obj.name);
        if (choosedIndex == index)
        {
            StopShowItem();
            rotSpeed = -MIN_SPEED;
            return;
        }

        if (choosedIndex != -1)
        {
            StopShowItem();
        }

        choosedIndex = index;
        rotSpeed = 0;

        // 点击选中，放大
        var uiObj = uiObjs[choosedIndex];
        uiObj.transform.DOKill();
        uiObj.transform.DOScale(Big_Scale, 0.5f);

        // 移到中间
        RotToCenter();

        // 播放视频
        PlayVideo(obj);
    }

    private void RotToCenter()
    {
        float itemCenterY = GetItemCenterY();
        Vector3 eulerAngles = uiParent.eulerAngles;
        eulerAngles.y = itemCenterY;
        systemCtrl = true;
        uiParentTween = uiParent.DORotate(eulerAngles, 0.4f, RotateMode.Fast).OnComplete(() =>
        {
            systemCtrl = false;
        });
    }

    private float GetItemCenterY()
    {
        float angle = 360f / numberOfObjects * choosedIndex;
        return -angle;
    }

    private void PlayVideo(GameObject obj)
    {
        VideoPlayer videoPlayer = obj.transform.Find("Canvas/Image/VideoPlayer").GetComponent<VideoPlayer>();
        videoPlayer.Play();
        Image image = obj.transform.Find("Canvas/Image/Image").GetComponent<Image>();
        image.gameObject.SetActive(false);
    }

    private void VideoEnd(VideoPlayer videoPlayer)
    {
        StopShowItem();
        rotSpeed = -MIN_SPEED;
    }

    private void OnStartClick()
    {
        foreach (var uiObj in uiObjs)
        {
            uiObj.SetActive(false);
        }
        Vector3 eulerAngles = uiParent.eulerAngles;
        eulerAngles.y = 180;
        uiParent.eulerAngles = eulerAngles;
        //rotSpeed = 0;
        //systemCtrl = true;
        isStarting = true;
        isEnding = false;

        rotSpeed = -MIN_SPEED;
        //uiParentTween = uiParent.DORotate(Vector3.down * 540, 6f, RotateMode.WorldAxisAdd).SetEase(Ease.Linear).OnComplete(() =>
        //{
        //    systemCtrl = false;
        //    isStarting = false;
        //    rotSpeed = -MIN_SPEED;
        //    uiParentTween = null;
        //});
    }

    private void OnEndClick()
    {
        endInitRot = uiParent.transform.eulerAngles.y;
        Debug.Log("EndInitRot:" + endInitRot);
        rotSpeed = 0;
        systemCtrl = true;
        isStarting = false;
        isEnding = true;
        uiParent.DORotate(Vector3.down * 360, 6f, RotateMode.WorldAxisAdd).OnComplete(() =>
        {
            systemCtrl = false;
            isEnding = false;
        });
    }

    private void OnCNClick()
    {
        //language = Language.CN;
        //RefreshLanguage();
        AppConst.language = Language.CN;
        SceneManager.LoadScene("LunBoTu");
    }

    private void OnENClick()
    {
        //language = Language.EN;
        //RefreshLanguage();
        AppConst.language = Language.EN;
        SceneManager.LoadScene("LunBoTu");
    }

    private void RefreshLanguage()
    {
        cnBtn.gameObject.SetActive(language == Language.EN);
        enBtn.gameObject.SetActive(language == Language.CN);
        for (int i = 0; i < uiObjs.Count; i++)
        {
            var uiObj = uiObjs[i];
            if (uiObj != null)
            {
                if (Videos.Count > i)
                {
                    string nameSpritePath = "Sprites/ContrName/" + (language == Language.CN ? "cn_" : "en_") + Videos[i];
                    var nameImage = uiObj.transform.Find("Canvas/Image/NameImage").GetComponent<Image>();
                    nameImage.sprite = Resources.Load<Sprite>(nameSpritePath);
                    nameImage.SetNativeSize();
                }
            }
        }
    }

    private void Update()
    {
        SetEffects();
        float deltaTime = Time.deltaTime;

        if (PlayerControl())
        {
            RefreshMouseSpeed(deltaTime);
            if (choosedIndex >= 0)
            {
                if (rotSpeed != 0)
                {
                    // 在选中后滑动屏幕，则恢复原大小
                    StopShowItem();
                }
            }
            else
            {
                if (lastMousePos.Equals(INIT_POS_VALUE))
                {
                    if (rotSpeed >= 0)
                    {
                        rotSpeed = Mathf.Clamp(rotSpeed, MIN_SPEED, MAX_SPEED);
                    }
                    else
                    {
                        rotSpeed = Mathf.Clamp(rotSpeed, -MAX_SPEED, -MIN_SPEED);
                    }
                }
                RotateUIParent();
            }
        }
        //else
        {
            RefreshStartEndActive();
        }
        LookAtCamera();
    }

    private void StopShowItem()
    {
        var uiObj = uiObjs[choosedIndex];
        uiObj.transform.DOKill();
        uiObj.transform.DOScale(Normal_Scale, 0.3f);
        choosedIndex = -1;
        VideoPlayer videoPlayer = uiObj.transform.Find("Canvas/Image/VideoPlayer").GetComponent<VideoPlayer>();
        videoPlayer.Stop();
        videoPlayer.Prepare();
        Image image = uiObj.transform.Find("Canvas/Image/Image").GetComponent<Image>();
        image.gameObject.SetActive(true);
    }

    /// <summary>
    /// x是否在a和b之间
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <param name="x"></param>
    /// <returns></returns>
    private bool ContainsValue(float a, float b, float x)
    {
        float min = a > b ? b : a;
        float max = a > b ? a : b;
        return Mathf.Clamp(x, min, max).Equals(x);
    }

    /// <summary>
    /// 是否由玩家控制
    /// </summary>
    /// <returns></returns>
    private bool PlayerControl()
    {
        return !systemCtrl;
    }

    /// <summary>
    /// 刷新鼠标速度
    /// </summary>
    private void RefreshMouseSpeed(float deltaTime)
    {
        //Vector3 touchPos = Vector3.one * int.MinValue;
        //if (Input.GetMouseButton(0))
        //{
        //    touchPos = Input.mousePosition;
        //}
        //else if (Input.touchCount > 0)
        //{
        //    touchPos = Input.GetTouch(0).position;

        //}

        //if (!touchPos.Equals(Vector3.one * int.MinValue))
        //{
        //    // 上一个鼠标位置有效
        //    if (!lastMousePos.Equals(INIT_POS_VALUE))
        //    {
        //        Vector3 offset = touchPos - lastMousePos;
        //        // (距离 / 时间) * 系数
        //        rotSpeed = offset.x / deltaTime * SPEED_COE;
        //    }
        //    lastMousePos = touchPos;
        //}
        //else
        //{
        //    lastMousePos = INIT_POS_VALUE;
        //    //RotSpeedAttenuation(deltaTime);
        //}
    }

    /// <summary>
    /// 速度衰减
    /// </summary>
    private void RotSpeedAttenuation(float deltaTime)
    {
        // 鼠标没拖动，就计算速度衰减
        if (rotSpeed != 0)
        {
            float absSpeed = Mathf.Abs(rotSpeed);
            float SpeedAttenuationCoe = GetSpeedAttenuationCoe(absSpeed);
            absSpeed -= deltaTime * GetSpeedAttenuationCoe(absSpeed);
            if (absSpeed < 0)
            {
                absSpeed = 0;
            }
            rotSpeed = rotSpeed > 0 ? absSpeed : -absSpeed;
        }
    }

    private float GetSpeedAttenuationCoe(float absSpeed)
    {
        for (int i = 0; i < SPEED_ATTENUATION_LEVEL.Count; i++)
        {
            if (absSpeed < SPEED_ATTENUATION_LEVEL[i])
            {
                return SPEED_ATTENUATION_COE[i];
            }
        }
        return SPEED_ATTENUATION_COE.Last();
    }

    private float GetNextUIRot()
    {
        float rot = uiParent.eulerAngles.y;
        float absRotIn360 = Mathf.Abs(rot) % 360;
        float rotNow = rot > 0 ? absRotIn360 : -absRotIn360;
        float singleRot = 360 / numberOfObjects;
        return ((int)(rotNow / singleRot) + (rotSpeed > 0 ? 1 : 0)) * singleRot;
    }

    /// <summary>
    /// 旋转UI父级
    /// </summary>
    private void RotateUIParent()
    {
        if (rotSpeed != 0)
        {
            uiParent.eulerAngles += Vector3.up * rotSpeed;
        }
    }

    /// <summary>
    /// 所有UI面向相机
    /// </summary>
    private void LookAtCamera()
    {
        if (uiObjs != null && uiObjs.Count > 0)
        {
            foreach (GameObject obj in uiObjs)
            {
                obj.transform.LookAt(cameraTran.position);
            }
        }
    }

    private void RefreshStartEndActive()
    {
        if (isStarting)
        {
            float uiRotNow = uiParent.eulerAngles.y;
            if (uiRotNow > 180)
            {
                uiRotNow -= 360;
            }
            uiRotNow = -uiRotNow;
            for (int i = 0; i < uiObjs.Count; i++)
            {
                var uiObj = uiObjs[i];
                if (uiRotNow >= i * (360 / numberOfObjects) - 180)
                {
                    if (i < Videos.Count)
                    {
                        if (!uiObj.activeSelf)
                        {
                            //Debug.Log(" uirotNow:" + uiRotNow + ",   i * (360 / numberOfObjects):" + (i * (360 / numberOfObjects)));
                            uiObj.SetActive(true);
                            VideoPlayer videoPlayer = uiObj.transform.Find("Canvas/Image/VideoPlayer").GetComponent<VideoPlayer>();
                            videoPlayer.prepareCompleted += VideoPrepareComplete;
                            videoPlayer.Prepare();
                        }
                    }
                }
            }
        }

        if (isEnding)
        {
            float distance = -1;
            int farIndex = -1;
            for (int i = 0; i < uiObjs.Count; i++)
            {
                float uiDis = Vector3.Distance(uiObjs[i].transform.position, cameraTran.position);
                if (uiDis > distance)
                {
                    farIndex = i;
                    distance = uiDis;
                }
            }
            uiObjs[farIndex].SetActive(false);
        }
    }

    private void VideoPrepareComplete(VideoPlayer source)
    {
        source.Pause();
        source.frame = 0;
    }
}
